加载和运行 Yarn 叙事脚本
欢迎来到 YarnRunner 功能库使用教程。在本教程中,我们将指导您如何加载和运行您在前一教程中编写的 Yarn 叙事脚本。
1. 初始化 YarnRunner
- Lua
- Teal
- TypeScript
- YueScript
首先确保您已正确地导入所有必需的模块。以下是本教程示例中我们需要的模块:
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
为了确保我们可以找到 Yarn 脚本,我们需要设置正确的搜索路径。如果 Yarn 脚本和程序模块在同一个目录下时我们可以增加如下代码:
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
接下来,假设我们要加载的 Yarn 文件名为 "tutorial.yarn",起始节点的标题名称为 "Start",则编写如下代码:
local runner = YarnRunner("tutorial.yarn", "Start")
首先确保您已正确地导入所有必需的模块。以下是本教程示例中我们需要的模块:
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
为了确保我们可以找到 Yarn 脚本,我们需要设置正确的搜索路径。如果 Yarn 脚本和程序模块在同一个目录下时我们可以增加如下代码:
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
接下来,假设我们要加载的 Yarn 文件名为 "tutorial.yarn",起始节点的标题名称为 "Start",则编写如下代码:
local runner = YarnRunner("tutorial.yarn", "Start")
首先确保您已正确地导入所有必需的模块。以下是本教程示例中我们需要的模块:
import { Content, Path, Node, Director, YarnRunner } from "Dora";
为了确保我们可以找到 Yarn 脚本,我们需要设置正确的搜索路径。如果 Yarn 脚本和程序模块在同一个目录下时我们可以增加如下代码:
const path = Path.getScriptPath(...);
Content.insertSearchPath(1, path);
接下来,假设我们要加载的 Yarn 文件名为 "tutorial.yarn",起始节点的标题名称 为 "Start",则编写如下代码:
const runner = YarnRunner("tutorial.yarn", "Start");
首先确保您已经导入所有必需的模块。
_ENV = Dora
import "YarnRunner"
为了确保我们可以找到 Yarn 脚本,我们需要设置正确的搜索路径。如果 Yarn 脚本和程序模块在同一个目录下时我们可以增加如下代码:
path = Path\getScriptPath ...
Content\insertSearchPath 1, path
接下来,假设我们要加载的 Yarn 文件名为 "tutorial.yarn",起始节点的标题名称为 "Start",则编写如下代码:
runner = YarnRunner "tutorial.yarn", "Start"
2. 执行和展示叙事内容
我们定义了一个 advance
函数,该函数可以读取并展示 Yarn 脚本中的文本内容或选项。根据叙事的内容,它还可以展示角色的名字:
- Lua
- Teal
- TypeScript
- YueScript
-- advance 函数的参数是一个可选的整数,代表玩家选择的选项索引。
-- 当第一次调用此函数或在不需要选择时,我们将传递 nil
local function advance(option)
-- 函数首先调用 runner:advance(option) 来获取 Yarn 脚本的下一部分内容。
-- 这将返回两个值:一个动作类型和一个结果。
local action, result = runner:advance(option)
-- 根据动作类型,选择如何处理结果。
if action == "Text" then
-- 如果动作是 "Text",则结果会是一个 TextResult 对象,
-- 其中包含文本内容和任何相关的标记(例如角色名)。
-- 检查标记,提取角色名(如果存在)并打印出文本内容。
local characterName = ""
local marks = result.marks
if marks then
for i = 1, #marks do
local mark = marks[i]
if mark.name == "char" then
characterName = mark.attrs.name .. ": "
end
end
end
print(characterName .. result.text)
elseif action == "Option" then
-- 如果动作是 "Option",则结果会是一个 OptionResult 对象,
-- 其中包含了一个或多个选项。函数会遍历这些选项并打印它们,
-- 玩家稍后可以选择它们。
for i, op in ipairs(result) do
if op then
print("[" .. tostring(i) .. "]: " .. op.text)
end
end
else
-- 对于其他动作(例如错误),函数将直接打印结果。
print(result)
end
end
-- advance 函数的参数是一个可选的整数,代表玩家选择的选项索引。
-- 当第一次调用此函数或在不需要选择时,我们将传递 nil
local function advance(option?: integer)
-- 函数首先调用 runner:advance(option) 来获取 Yarn 脚本的下一部分内容。
-- 这将返回两个值:一个动作类型和一个结果。
local action, result = runner:advance(option)
-- 根据动作类型,选择如何处理结果。
if action == "Text" then
-- 如果动作是 "Text",则结果会是一个 TextResult 对象,
-- 其中包含文本内容和任何相关的标记(例如角色名)。
local textResult = result as YarnRunner.TextResult
-- 检查标记,提取角色名(如果存在)并打印出文本内容。
local characterName = ""
local marks = textResult.marks
if not (marks is nil) then
for i = 1, #marks do
local mark = marks[i]
if mark.name == "char" then
characterName = tostring(mark.attrs.name) .. ": "
end
end
end
print(characterName .. textResult.text)
elseif action == "Option" then
-- 如果动作是 "Option",则结果会是一个 OptionResult 对象,
-- 其中包含了一个或多个选项。函数会遍历这些选项并打印它们,
-- 玩家稍后可以选择它们。
local optionResult = result as YarnRunner.OptionResult
for i, op in ipairs(optionResult) do
if op and not (op is boolean) then
print("[" .. tostring(i) .. "]: " .. op.text)
end
end
else
-- 对于其他动作(例如错误),函数将直接打印结果。
print(result)
end
end
// advance 函数的参数是一个可选的整数,代表玩家选择的选项索引。
// 当第一次调用此函数或在不需要选择时,我们将传递 null
function advance(option?: number): void {
// 函数首先调用 runner.advance(option) 来获取 Yarn 脚本的下一部分内容。
// 这将返回两个值:一个动作类型和一个结果。
const [action, result] = runner.advance(option);
// 根据动作类型,选择如何处理结果。
switch (action) {
case "Text":
// 如果动作是 "Text",则结果会是一个 TextResult 对象,
// 其中包含文本内容和任何相关的标记(例如角色名)。
// 检查标记,提取角色名(如果存在)并打印出文本内容。
let characterName = "";
const marks = result.marks;
if (marks) {
for (const mark of marks) {
if (mark.name === "char") {
characterName = `${mark.attrs?.name}: `;
}
}
}
print(characterName + result.text);
break;
case "Option":
// 如果动作是 "Option",则结果会是一个 OptionResult 对象,
// 其中包含了一个或多个选项。函数会遍历这些选项并打印它们,
// 玩家稍后可以选择它们。
const optionResult = result;
for (let i = 0; i < optionResult.length; i++) {
const op = optionResult[i];
if (op && op !== true) {
print(`[${i}]: ${op.text}`);
}
}
break;
default:
// 对于其他动作(例如错误),函数将直接打印结果。
print(result);
break;
}
}
-- advance 函数的参数是一个可选的整数,代表玩家选择的选项索引。
-- 当第一次调用此函数或在不需要选择时,我们将传递 nil
advance = (option) ->
-- 函数首先调用 runner\advance 来获取 Yarn 脚本的下一部分内容。
-- 这将返回两个值:一个动作类型和一个结果。
action, result = runner\advance option
-- 根据动作类型,选择如何处理结果。
switch action when "Text"
-- 如果动作是 "Text",则结果会是一个 TextResult 对象,
-- 其中包含文本内容和任何相关的标记(例如角色名)。
-- 检查标记,提取角色名(如果存在)并打印出文本内容。
charName = ""
if result.marks
for mark in *result.marks
switch mark when {name: attr, attrs: {:name}}
charName = "#{name}: " if attr == "char"
print charName .. result.text
when "Option"
-- 如果动作是 "Option",则结果会是一个 OptionResult 对象,
-- 其中包含了一个或多个选项。函数会遍历这些选项并打印它们,
-- 玩家稍后可以选择它们。
for i, op in ipairs result
print "[#{i}]: #{op.text}" if op
else
-- 对于其他动作(例如错误),函数将直接打印结果。
print result
3. 启动叙事
要启动叙事,我们只需调用 advance
函数,不带任何参数:
- Lua
- Teal
- TypeScript
- YueScript
advance()
advance()
advance();
advance!
4. 响应用户输入
为了能够让玩家与叙事互动,我们需要一个节点来捕获和响应用户的输入。我们创建一个节点,并为其指定一个名为 "go" 的信号槽。当这个信号被触发时,它将再次调用 advance
函数,并传递玩家选择的选项:
- Lua
- Teal
- TypeScript
- YueScript
local node = Node()
node:gslot("go", function(option)
advance(option)
end)
node:addTo(Director.entry)
local node = Node()
node:gslot("go", function(option: nil | integer)
advance(option)
end)
node:addTo(Director.entry)
const node = Node();
node.gslot("go", (option: number | null) => {
advance(option);
});
node.addTo(Director.entry);
with Node!
\gslot "go", (option) -> advance option
\addTo Director.entry
这里只是为了能快速进行测试而注册了一个全局的事件监听器。在实际的游戏开发中会需要通过编写UI交互的逻辑来完成使用。有了这个名叫“go”的全局事件监听器后。我们就可以通过打开 Dora SSR 的控制台界面,在下面的命令行中输入 emit 'go'
来继续推进对话,输入 emit 'go', 1
来选择对话分支完成交互式的测试运行了。
5. 添加自定义命令和状态
您可以通过给 YarnRunner
传递 command
和 state
参数来添加自定义命令和初始状态的变量。command
参数是一个包含可以执行命令的回调函数的 Lua 表,state
参数是一个包含预定义变量的表格。以下是一个示例:
- Lua
- Teal
- TypeScript
- YueScript
local runner = YarnRunner("tutorial.yarn", "Start", {
playerScore = 100
}, {
print = print
})
local runner = YarnRunner("tutorial.yarn", "Start", {
playerScore = 100
}, {
print = print
})
const runner = YarnRunner("tutorial.yarn", "Start", {
playerScore: 100
}, {
print: print
})
runner = YarnRunner "tutorial.yarn", "Start", {
playerScore: 100
}, {
print: print
}
然后在 Yarn 脚本中,您就可以通过使用 <<set $变量名 = 表达式>>
命令来改变初始变量的值,并通过自定义的命令 <<print $变量名>>
命令来打印变量的值:
<<set $playerScore = $playerScore + 200>>
<<print $playerScore>>
6. 结论
现在,您已经设置好了所有必要的代码来加载和运行 Yarn 叙事脚本。您可以运行上述脚本来开始您的互动叙事,玩家可以通过选择选项来与叙事互动。祝您创作愉快!